#include "GameApp.h"

/*******************************************************************
					PUBLIC Class Functions
*******************************************************************/


// Class constructor, initialize some variables
GameApp::GameApp() : m_pFramework(NULL), m_AA(false), m_deltaX(0), m_deltaY(0), m_objsRenderedCount(0), m_n(false) {
	m_mousePosition.x = 0;		m_mousePosition.y = 0;
	m_leftMouseButton = false;	m_rightMouseButton = false;
	srand((unsigned)time(NULL));
	careerScore = 0;
	credits = 0;
	slowmotion = false;
	m_TDView = true;
	m_outOfBoundsTimer = g_OutOfBoundsTimeMax;
}

// Release data
void GameApp::Release() {
	SAFE_RELEASE(m_pFramework);
}

// Set the framework
void GameApp::SetFramework(Framework* pFramework) {
	m_pFramework = pFramework;
}

// Initialize the class
bool GameApp::Initialize() {
	InitializeCamera(); // function call to initialize the camera
	return true;
}


// Initialize the camera
void GameApp::InitializeCamera() {
	m_camera.setPosition(new D3DXVECTOR3(0.0f, 150.0f, -10.0f));
	m_camera.setLook(new D3DXVECTOR3(0.0f, 0.0f, 0.0f));
	D3DXVECTOR3 foo;
	foo.x = 0.0f;
	foo.y = 0.0f;
	foo.z = 0.0f;
	m_camera.Update(&foo, true);
}

void GameApp::InitializeFonts(LPDIRECT3DDEVICE9 pDevice) {
	m_font.Initialize(pDevice, "Arial", 25); // initialize m_font
	m_smallFont.Initialize(pDevice, "Arial", 32);
	m_mediumFont.Initialize(pDevice,"Arial", 50);
	m_largeFont.Initialize(pDevice, "Times New Roman", 100); // initialize m_largeFont
}

// Initialize the world light
void GameApp::InitializeLight(LPDIRECT3DDEVICE9 pDevice) {
	m_lights[0].Initialize(D3DLIGHT_DIRECTIONAL, 5000.0f); // function call to reset the light settings
	m_lights[0].setLight(pDevice, 0);
	m_lights[0].enableLight(pDevice, true);
}

// Initialize the night vision light
void GameApp::InitializeLightNV(LPDIRECT3DDEVICE9 pDevice) {
	m_lights[1].Initialize(D3DLIGHT_DIRECTIONAL, 5000.0f); // function call to reset the light settings
	m_lights[1].setDifAbs(0.1f,0.5f,0.1f);
	m_lights[1].setSpeAbs(0.0f,0.3f,0.0f);
	m_lights[1].setAmbAbs(0.0f,0.2f,0.0f);
	m_lights[1].setLight(pDevice, 1);
	m_lights[1].enableLight(pDevice, false);
}

void GameApp::InitializeMuzzleFlashLights(LPDIRECT3DDEVICE9 pDevice) {
	for(int i=g_PlayerLightsStart; i<g_MAX_LIGHTS; i++) {
		m_lights[i].Initialize(D3DLIGHT_POINT, g_MuzzleFlashRange);
		m_lights[i].setPosAbs(0.0f,0.0f,0.0f);
		m_lights[i].setLight(pDevice,i);
		m_lights[i].enableLight(pDevice,false);
	}
}

void GameApp::InitializeGameMarkers(LPDIRECT3DDEVICE9 pDevice) {
	for(eIter = m_lEnvObjects.begin(); eIter != m_lEnvObjects.end(); eIter++) {
		PRINT(eIter->alignment.c_str());	NEXT_LINE;
		if(eIter->alignment == "Enemy" /*&& eIter->health > 0.0f*/) {
			MarkerObject* t_markObject = new MarkerObject(g_AttMarkerFile);
			if(!t_markObject->Initialize(pDevice)) {
				SHOWERROR("t_markObject.Initialize() - Failed", __FILE__, __LINE__);
			}
			t_markObject->meshInst.translateAbs(eIter->meshInst.getXPosition(),eIter->meshInst.getYPosition() + g_MarkerYOffset,
				eIter->meshInst.getZPosition());
			t_markObject->envObj = &(*eIter);
			m_lMarkerObjects.push_front(*t_markObject);
		} else if(eIter->alignment == "Player" /*&& eIter->health > 0.0f*/) {
			MarkerObject* t_markObject = new MarkerObject(g_DefMarkerFile);
			if(!t_markObject->Initialize(pDevice)) {
				SHOWERROR("t_markObject.Initialize() - Failed", __FILE__, __LINE__);
			}
			t_markObject->meshInst.translateAbs(eIter->meshInst.getXPosition(),eIter->meshInst.getYPosition() + g_MarkerYOffset,
				eIter->meshInst.getZPosition());
			t_markObject->envObj = &(*eIter);
			m_lMarkerObjects.push_front(*t_markObject);
		}
	}
}

// On the creation of the device, do some more initialization.
// This function differs from GameApp::Initialize() since the pDevice parameter is passed and used in
// some of the functions in this function.
// GameApp::Initialize() cannot use pDevice as a parameter since it is called in WinMain, and there is
// no pDevice that can be passed in since it is created afterward.
void GameApp::OnCreateDevice(LPDIRECT3DDEVICE9 pDevice) {
	ParsePlayerData(pDevice, "Saves\\NewPlayer.txt");
	
	D3DXCreateSprite(pDevice, &m_pTextSprite); // create the sprite to be used by the 2D graphics (text)
	
	InitializeFonts(pDevice);
	
	InitializeMuzzleFlashLights(pDevice); // initialize muzzle flash lights
	InitializeLight(pDevice); // initialize the light
	InitializeLightNV(pDevice); // initialize the night vision light

	//OpenMap(pDevice,"Maps\\TestMapTwoNight.wm");
	OpenMap(pDevice,"Maps\\SmallVerticalMapOne.wm");
	//OpenMap(pDevice,"Maps\\TestOne.wm");

	InitializeGameMarkers(pDevice);
	setPlayerData(pDevice);

	// Initialize the player's direction/destination point (for debugging purposes)
	m_playerDest.modelFile = "Graphics\\Models\\MiscObjects\\Point.x";
			m_playerDest.Initialize(pDevice);
			m_playerDest.name = "PlayerDest";
			m_playerDest.meshInst.translateAbs(0,0,0);

	// set unit data
	for(wIter = m_lWorldObjects.begin(); wIter != m_lWorldObjects.end(); wIter++) {
		ParseUnitData(wIter);
		scaleDataToLevel(wIter);
		addRandomancyToData(wIter);
	}

	// set env data
	for(eIter = m_lEnvObjects.begin(); eIter != m_lEnvObjects.end(); eIter++) {
		ParseEnvData(eIter);
		eIter->InitializeRuinMesh(pDevice);
	}

	// lari
	// set map bounds
	for(list<MiscObject>::iterator it=  m_lMiscObjects.begin(); it != m_lMiscObjects.end(); it++) {
		if(it->purpose.compare("MapCornerTL") == 0){
			m_mapBoundsTL = *it->meshInst.getPosition();
		}
		else if(it->purpose.compare("MapCornerBR") == 0){
			m_mapBoundsBR = *it->meshInst.getPosition();
		}
	}
	// end:lari

	Sound snd;
	snd.initDirectSound(m_pFramework->getHandle());
	snd.setFilename("Sound\\MachineGun1.wav");
	snd.LoadWaveToSoundBuffer();
	snd.setVol(0);
	snd.playSound();
	snd.stopSound();
	snd.setVol(100);
}

// When the device is reset, do the following
void GameApp::OnResetDevice(LPDIRECT3DDEVICE9 pDevice) {
	m_pTextSprite->OnResetDevice();
	m_font.OnResetDevice();

	// set projection
	m_camera.setAspectRatio((float)m_pFramework->getWidth() / (float)m_pFramework->getHeight());
	pDevice->SetTransform(D3DTS_PROJECTION, m_camera.getProjectionMatrix());

	// set antialising render states
	if(m_AA) {
		pDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, TRUE);
		pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
	}

	// set render states
	pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
	pDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
	pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
	pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);

	// turn on culling
	pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	// enable alpha blending
	pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

	// light settings
	pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	pDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);
	pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
	pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);

	// new, dont know how they will affect the program
	pDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 8);					// anisotropic level
	pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);	// minification
	pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);			// magnification
	pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);			// mipmap
}

// When the device is lost, call the OnLostDevice functions of the following components.
void GameApp::OnLostDevice() {
	m_pTextSprite->OnLostDevice();
	m_font.OnLostDevice();
}

// Release certain objects when the device is to be stopped
void GameApp::OnDestroyDevice() {
	SAFE_RELEASE(m_pTextSprite);
	m_font.Release();
}

// Updates for general components of the application are called here
void GameApp::OnUpdateFrame(LPDIRECT3DDEVICE9 pDevice, float elapsedTime) {
	if(slowmotion) {
		g_CurrentModifier = g_SlowMotionModifier;
		elapsedTime = elapsedTime * g_CurrentModifier;
	}
	// Self-explanatory updates
	UpdateNightVision(pDevice);
	UpdateLights(pDevice);
	UpdatePlayer(pDevice,elapsedTime);
	UpdateAI(pDevice,elapsedTime);
	UpdateProjectiles(pDevice,elapsedTime);
	UpdateCamera();
	UpdateHUD();
	UpdateEnvObjects(pDevice);
	UpdateMarkers(elapsedTime);

	slowmotion = false;
	g_CurrentModifier = 1.0f;
}

// Rendering calls for general components of the application
void GameApp::OnRenderFrame(LPDIRECT3DDEVICE9 pDevice, float elapsedTime) {
	m_objsRenderedCount = 0; // count resetted

	// Self-explanatory rendering
	BeginScene(pDevice);
	
	RenderGround(pDevice);
	RenderEnvObjects(pDevice);
	RenderMarkerObjects(pDevice);
	RenderProjectiles(pDevice);
	RenderWorldObjects(pDevice);
	RenderPlayer(pDevice);
	//RenderPlayerDirPoint(pDevice); // for debugging purposes
	//RenderMiscObjects(pDevice); // for debugging purposes
	RenderText();
	
	EndScene(pDevice);
}

// Process the user's input
// When possible, the input will be saved then used in the Update calls (handle input will not update aspects of
// the application, only saves the input in the GameApp's variables).
void GameApp::ProcessInput(long xDelta, long yDelta, long zDelta, bool* pMouseButtons, bool* pPressedKeys, float elapsedTime, HWND hWnd) {
	// Get mouse information
	POINT ptCursor;
	GetCursorPos(&ptCursor);
	ScreenToClient(hWnd, &ptCursor);
	m_mousePosition.x = ptCursor.x;		m_mousePosition.y = ptCursor.y;
	m_deltaX = xDelta;		m_deltaY = yDelta;

	// Check for specific input
	// Mouse buttons...
	if(pMouseButtons[0]) { // left mouse button
		m_leftMouseButton = true;
	}
	if(pMouseButtons[1]) { // right mouse button
		m_rightMouseButton = true;
	}
	// Keyboard buttons are self-explanatory...
	if(pPressedKeys[DIK_W]) {
	}
	if(pPressedKeys[DIK_A]) {
	}
	if(pPressedKeys[DIK_S]) {
	}
	if(pPressedKeys[DIK_D]) {
	}
	if(pPressedKeys[DIK_N]) {
		m_pFramework->LockKey(DIK_N); // locks the specific key (only counts once until key is released and clicked again)
		m_n = true;
	}
	if(pPressedKeys[DIK_SPACE]) {
		slowmotion = true;
	}
	if(pPressedKeys[DIK_Z]) {
		m_pFramework->LockKey(DIK_Z);
		if(m_TDView)
			m_TDView = false;
		else
			m_TDView = true;
	}
	if(pPressedKeys[DIK_F]) {
		m_pFramework->LockKey(DIK_F); // locks the specific key (only counts once until key is released and clicked again)
		PRINT("F");
	}
	if(pPressedKeys[DIK_ESCAPE]) { // exit the program
		m_pFramework->LockKey(DIK_ESCAPE);
		PostQuitMessage(0);
	}
	if(pPressedKeys[DIK_F1]) {
		for(eIter = m_lEnvObjects.begin(); eIter != m_lEnvObjects.end(); eIter++) {
			eIter->health = 0.0f;
		}
	}
	if(pPressedKeys[DIK_F2]) {
	}
	if(pPressedKeys[DIK_F5]) {
	}
	if(pPressedKeys[DIK_F6]) {
	}
}

// Set AntiAlising to True or False
void GameApp::setAA(bool a_AA) {
	m_AA = a_AA;
}

// Parser to import (.wm) maps created in the WorldEditor.
// **Does not import specific object (usually unit) data such as physics information**
void GameApp::OpenMap(LPDIRECT3DDEVICE9 pDevice, string file) {
	
	fstream in(file.c_str()); // set fstream in() to a specific file from the function parameter
	m_lWorldObjects.clear();
	m_lEnvObjects.clear();
	m_lMiscObjects.clear();
	m_lProjObjects.clear();

	// temporary variables to hold imported information

	string version;

	// Light
	// read order: dirXYZ, difRGB, speRGB, ambRGB
	float dX, dY, dZ, dR, dG, dB, sR, sG, sB, aR, aB, aG;
	// Object
	// read order: mFile, dFile, iLoc, name, align, posXYZ, scXYZ, roXYZ
	string tag, mFile, dFile, iLoc, name, align;
	float locX, locY, locZ, scX, scY, scZ, roX, roY, roZ;
	// Unit
	// read order: lvl, val, cMove, st, grp
	string cMove, st;
	int lvl, val, grp;
	// Env
	// read order: val
	//int val;
	// Misc
	// read order: pur, hRad, ord, type, grp, sFile
	string pur, type, sFile;
	int ord; // grp;
	float hRad;

	sprintf_s(m_loading, sizeof(m_loading), "Please Wait");
	sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Reading Map File");
	RenderLoading(pDevice);
	Sleep(1500);

	in >> version;
	// Tags will give you an indication of their purpose, no rocket-science here...
	in >> tag;
	while(tag != "<END>") {
		if(tag == "<LIGHT>") {
			sprintf_s(m_loading, sizeof(m_loading), "Please Wait.");
			sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Setting World Light");
			RenderLoading(pDevice);

			in >> dX;	in >> dY;	in >> dZ;
			in >> dR;	in >> dG;	in >> dB;
			in >> sR;	in >> sG;	in >> sB;
			in >> aR;	in >> aG;	in >> aB;

			m_lights[0].setSpeAbs(sR,sG,sB);
			m_lights[0].setAmbAbs(aR,aG,aB);
			m_lights[0].setDifAbs(dR,dG,dB);
			m_lights[0].setDirAbs(dX,dY,dZ);
			
			m_lights[0].setLight(pDevice,0);
		}
		if(tag == "<MAP>") {
			sprintf_s(m_loading, sizeof(m_loading), "Please Wait..");
			sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Loading Terrain");
			RenderLoading(pDevice);

			in >> mFile;	in >> dFile;	in >> iLoc;		in >> name;		in >> align;
			in >> locX;		in >> locY;		in >> locZ;
			in >> scX;		in >> scY;		in >> scZ;
			in >> roX;		in >> roY;		in >> roZ;

			m_ground.Release();
			
			m_ground.modelFile = mFile;
			
			if(!m_ground.Initialize(pDevice)) {
				SHOWERROR("m_ground.Initialize() - Failed", __FILE__, __LINE__);
			}

			m_ground.dataFile = dFile;		m_ground.name = name;		m_ground.alignment = align;
			m_ground.meshInst.translateAbs(locX,locY,locZ);
			m_ground.meshInst.scaleAbs(scX,scY,scZ);
			m_ground.meshInst.rotateAbs(ToRad(roX),ToRad(roY),ToRad(roZ));
		}
		if(tag == "<UNIT>") {
			sprintf_s(m_loading, sizeof(m_loading), "Please Wait...");
			sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Loading Units");
			RenderLoading(pDevice);
	
			in >> mFile;	in >> dFile;	in >> iLoc;		in >> name;		in >> align;
			in >> locX;		in >> locY;		in >> locZ;
			in >> scX;		in >> scY;		in >> scZ;
			in >> roX;		in >> roY;		in >> roZ;
			in >> lvl;		in >> val;		in >> cMove;	in >> st;		in >> grp;

			WorldObject* t_wObject = new WorldObject(mFile);
			
			t_wObject->meshInst.scaleAbs(scX,scY,scZ);
			if(!t_wObject->Initialize(pDevice)) {
				SHOWERROR("t_wObject.Initialize() - Failed", __FILE__, __LINE__);
			}

			t_wObject->dataFile = dFile;	t_wObject->name = name;		t_wObject->alignment = align;
			t_wObject->meshInst.translateAbs(locX,locY,locZ); 
			t_wObject->meshInst.setPrevPos(D3DXVECTOR3(locX,locY,locZ));
			t_wObject->meshInst.rotateAbs(roX,roY,roZ);
			t_wObject->unitInfo.level = lvl;	t_wObject->value = val;		t_wObject->unitInfo.group = grp;
			if(cMove == "True") {
				t_wObject->unitInfo.canMove = true;
			} else {
				t_wObject->unitInfo.canMove = false;
			}
			t_wObject->m_targetNonUnit = NULL;
			t_wObject->m_targetUnit = NULL;
			t_wObject->m_state = uninitialized;
			m_lWorldObjects.push_front(*t_wObject);
		}
		if(tag == "<ENV>") {
			sprintf_s(m_loading, sizeof(m_loading), "Please Wait....");
			sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Loading Environment Objects");
			RenderLoading(pDevice);

			in >> mFile;	in >> dFile;	in >> iLoc;		in >> name;		in >> align;
			in >> locX;		in >> locY;		in >> locZ;
			in >> scX;		in >> scY;		in >> scZ;
			in >> roX;		in >> roY;		in >> roZ;
			in >> val;
			
			EnvObject* t_eObject = new EnvObject(mFile);
			
			if(!t_eObject->Initialize(pDevice)) {
				SHOWERROR("t_wObject.Initialize() - Failed", __FILE__, __LINE__);
			}

			t_eObject->dataFile = dFile;	t_eObject->name = name;		t_eObject->alignment = align;
			t_eObject->meshInst.translateAbs(locX,locY,locZ);
			t_eObject->meshInst.scaleAbs(scX,scY,scZ);
			t_eObject->meshInst.rotateAbs(ToRad(roX),ToRad(roY),ToRad(roZ));
			t_eObject->value = val;

			m_lEnvObjects.push_front(*t_eObject);
		}
		if(tag == "<MISC>") {
			sprintf_s(m_loading, sizeof(m_loading), "Please Wait.....");
			sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Loading Misc. Objects");
			RenderLoading(pDevice);

			in >> mFile;	in >> dFile;	in >> iLoc;		in >> name;		in >> align;
			in >> locX;		in >> locY;		in >> locZ;
			in >> scX;		in >> scY;		in >> scZ;
			in >> roX;		in >> roY;		in >> roZ;
			in >> pur;		in >> hRad;		in >> ord;		in >> type;		in >> grp;
			if(version != "Version1.0") {
				in >> sFile;
			}

			MiscObject* t_mObject = new MiscObject(mFile);

			if(!t_mObject->Initialize(pDevice)) {
				SHOWERROR("t_mObject.Initialize() - Failed", __FILE__, __LINE__);
			}

			t_mObject->dataFile = dFile;	t_mObject->name = name;		t_mObject->alignment = align;
			t_mObject->meshInst.translateAbs(locX,locY,locZ);
			t_mObject->meshInst.scaleAbs(scX,scY,scZ);
			t_mObject->meshInst.rotateAbs(ToRad(roX),ToRad(roY),ToRad(roZ));
			t_mObject->purpose = pur;	t_mObject->hRadius = hRad;		t_mObject->order = ord;		t_mObject->type = type;		t_mObject->group = grp;
			
			m_lMiscObjects.push_front(*t_mObject);

			if(version != "Version1.0") {
				// push sound triggers into sound list
			}
		}
		in >> tag;
	}
	in.close();

	sprintf_s(m_loading, sizeof(m_loading), "COMPLETE");
	sprintf_s(m_loadingDesc, sizeof(m_loadingDesc), "Closing Map File");
	RenderLoading(pDevice);
	
}

void GameApp::ParsePlayerData(LPDIRECT3DDEVICE9 pDevice, string dataFile) {
	fstream in(dataFile.c_str());
	string tag = "?";
	m_playerInfo.weapons.clear();

	int cScore = 0, creds = 0, lvl = 0, hScore = 0;
	float hpRegen = 0.0f, maxHealth = 0.0f, maxVelocity = 0.0f, maxTurningSpeed = 0.0f, accuracyOffset = 0.0f, 
		fireRate = 0.0f, wMaxVelocity = 0.0f, range = 0.0f, weaponDmg = 0.0f;
	string name = "?", modelFile = "?", soundFile = "?", wModelFile = "?", wSoundFile = "?", 
		trigger = "?", type = "?", mName = "?";

	in >> name;
	in >> cScore;
	in >> creds;
	in >> hpRegen;
	in >> maxHealth;
	in >> modelFile;
	in >> maxVelocity;
	in >> maxTurningSpeed;
	in >> lvl;
	in >> soundFile;

	m_playerInfo.name = name;
	m_playerInfo.cScore = cScore;
	m_playerInfo.creds = creds;
	m_playerInfo.hpRegen = hpRegen;
	m_playerInfo.maxHealth = maxHealth;
	m_playerInfo.modelFile = modelFile;
	m_playerInfo.maxVelocity = maxVelocity;
	m_playerInfo.maxTurningSpeed = maxTurningSpeed;
	m_playerInfo.lvl = lvl;
	m_playerInfo.soundFile = soundFile;

	in >> tag;
	while(tag != "<END>") {
		if(tag == "<WEAPON>") {
			in >> accuracyOffset;
			in >> fireRate;
			in >> wMaxVelocity;
			in >> range;
			in >> weaponDmg;
			in >> wModelFile;
			in >> wSoundFile;
			in >> trigger;
			in >> type;

			WeaponInfo weaInfo;
			weaInfo.accuracyOffset = accuracyOffset;
			weaInfo.fireRate = fireRate;
			weaInfo.fireTime = 0.0f;
			weaInfo.maxVelocity = wMaxVelocity;
			weaInfo.range = range;
			weaInfo.modelFile = wModelFile;
			weaInfo.soundFile = wSoundFile;
			weaInfo.trigger = trigger;
			weaInfo.type = type;
			weaInfo.weaponDmg = weaponDmg;
			m_playerInfo.weapons.push_back(weaInfo);
		}
		if(tag == "<MAP>") {
			in >> mName;	in >> hScore;

			PlayerMapsInfo mapsInfo;
			mapsInfo.highscore = hScore;
			mapsInfo.map = mName;
			m_playerInfo.maps.push_back(mapsInfo);
		}
		in >> tag;
	}
	in.close();
}

void GameApp::ParseUnitData(ITERATOR(WorldObject) iter) {
	fstream in(iter->dataFile.c_str());
	string tag = "?";

	bool destructable = true;
	float LOS = 0.0f, hpRegen = 0.0f, maxHealth = 0.0f, maxVelocity = 0.0f, maxTurningSpeed = 0.0f, 
		accuracyOffset = 0.0f, fireRate = 0.0f, wMaxVelocity = 0.0f, 
		range = 0.0f, weaponDmg = 0.0f;
	string ruinFile = "?", soundFile = "?", modelFile = "?", wSoundFile = "?",
		trigger = "?", type = "?";


	in >> destructable;
	in >> hpRegen;
	in >> maxHealth;
	in >> ruinFile;
	in >> maxVelocity;
	in >> maxTurningSpeed;
	in >> LOS;
	in >> soundFile;

	iter->destructable = destructable;
	iter->hpRegen = hpRegen;
	iter->maxHealth = maxHealth;
	iter->health = maxHealth;
	iter->ruinFile = ruinFile;
	iter->physicsInfo.maxVelocity = maxVelocity;
	iter->physicsInfo.maxTurningSpeed = maxTurningSpeed;
	iter->unitInfo.LOS = LOS;
	iter->unitInfo.soundFile = soundFile;

	in >> tag;
	while(tag != "<END>") {
		if(tag == "<WEAPON>") {
			in >> accuracyOffset;
			in >> fireRate;
			in >> wMaxVelocity;
			in >> range;
			in >> weaponDmg;
			in >> modelFile;
			in >> wSoundFile;
			in >> trigger;
			in >> type;

			WeaponInfo weaInfo;
			weaInfo.accuracyOffset = accuracyOffset;
			weaInfo.fireRate = fireRate;
			weaInfo.fireTime = 0.0f;
			weaInfo.maxVelocity = wMaxVelocity;
			weaInfo.range = range;
			weaInfo.modelFile = modelFile;
			weaInfo.soundFile = wSoundFile;
			weaInfo.trigger = trigger;
			weaInfo.type = type;
			weaInfo.weaponDmg = weaponDmg;
			iter->weapons.push_back(weaInfo);
		}
		in >> tag;
	}
	in.close();
}

void GameApp::ParseEnvData(ITERATOR(EnvObject) iter) {
	fstream in(iter->dataFile.c_str());

	bool destructable = true;
	float maxHealth = 0.0f;
	string ruinFile = "?";

	in >> destructable;
	in >> maxHealth;
	in >> ruinFile;

	iter->destructable = destructable;
	iter->maxHealth = maxHealth;
	iter->health = maxHealth;
	iter->ruinFile = ruinFile;

	in.close();
}

void GameApp::setPlayerData(LPDIRECT3DDEVICE9 pDevice) {
	m_player.weapons.clear();
	bool playerFound = false;
	// Goes through the misc. objects to find the player's start location.
	// Once found, it will initialize the player in the location of the misc. object.
	for(mIter = m_lMiscObjects.begin(); mIter != m_lMiscObjects.end(); mIter++) {
		if(mIter->alignment == "Player" && mIter->purpose == "PlayerStart") {
			playerFound = true;

			// Initialize player information
			//m_player.modelFile = "Graphics\\Models\\UnitObjects\\P51Mustang.x";
			m_player.modelFile = m_playerInfo.modelFile;
			m_player.meshInst.scaleAbs(mIter->meshInst.getXScale(),mIter->meshInst.getYScale(),mIter->meshInst.getZScale());
			m_player.Initialize(pDevice);

			m_player.name = m_playerInfo.name;

			m_player.meshInst.translateAbs(mIter->meshInst.getXPosition(),mIter->meshInst.getYPosition(),mIter->meshInst.getZPosition());
			m_player.meshInst.rotateAbs(mIter->meshInst.getXRotation(),mIter->meshInst.getYRotation(),mIter->meshInst.getZRotation());
			m_player.physicsInfo.destination = D3DXVECTOR3(m_player.meshInst.getXPosition(),m_player.meshInst.getYPosition(), 
														m_player.meshInst.getZPosition()-g_playerDestDist);
			m_player.physicsInfo.dirPoint = D3DXVECTOR3(m_player.meshInst.getXPosition(),m_player.meshInst.getYPosition(), 
														m_player.meshInst.getZPosition()-g_playerDestDist);

			// returned degree rotation is correct, but sin() doesn't return what the calculator returns
			m_player.physicsInfo.dirPoint.x = sin(ToDeg(m_player.meshInst.getYRotation()));
			m_player.physicsInfo.dirPoint.y = m_player.meshInst.getYPosition();
			m_player.physicsInfo.dirPoint.z = cos(ToDeg(m_player.meshInst.getYRotation()));
			m_player.UpdateLookDirection(0.0f);
			m_player.ConstrictDirectionPoint();

			//m_player.physicsInfo.maxVelocity = 0.5;
			m_player.physicsInfo.maxVelocity = m_playerInfo.maxVelocity;
		}
	}

	if(!playerFound) {
		for(wIter = m_lWorldObjects.begin(); wIter != m_lWorldObjects.end(); wIter++) {
			if(wIter->alignment == "Player") {
				playerFound = true;

				// Initialize player information
				//m_player.modelFile = "Graphics\\Models\\UnitObjects\\P51Mustang.x";
				m_player.modelFile = m_playerInfo.modelFile;
				m_player.meshInst.scaleAbs(wIter->meshInst.getXScale(),wIter->meshInst.getYScale(),wIter->meshInst.getZScale());
				m_player.Initialize(pDevice);

				m_player.name = m_playerInfo.name;
				m_player.unitInfo.canMove = wIter->unitInfo.canMove;

				m_player.meshInst.translateAbs(wIter->meshInst.getXPosition(),wIter->meshInst.getYPosition(),wIter->meshInst.getZPosition());
				m_player.meshInst.rotateAbs(wIter->meshInst.getXRotation(),wIter->meshInst.getYRotation(),wIter->meshInst.getZRotation());
				m_player.physicsInfo.destination = D3DXVECTOR3(m_player.meshInst.getXPosition(),m_player.meshInst.getYPosition(), 
															m_player.meshInst.getZPosition()-g_playerDestDist);
				m_player.physicsInfo.dirPoint = D3DXVECTOR3(m_player.meshInst.getXPosition(),m_player.meshInst.getYPosition(), 
															m_player.meshInst.getZPosition()-g_playerDestDist);

				// rotation is correct, but sin() doesn't return what the calculator returns
				m_player.physicsInfo.dirPoint.x = sin(ToDeg(m_player.meshInst.getYRotation()));
				m_player.physicsInfo.dirPoint.y = m_player.meshInst.getYPosition();
				m_player.physicsInfo.dirPoint.z = cos(ToDeg(m_player.meshInst.getYRotation()));
				m_player.UpdateLookDirection(0.0f);
				m_player.ConstrictDirectionPoint();

				//m_player.physicsInfo.maxVelocity = 0.5;
				m_player.physicsInfo.maxVelocity = m_playerInfo.maxVelocity;

				m_lWorldObjects.erase(wIter);
				break;
			}
		}
	}

	careerScore = m_playerInfo.cScore;
	credits = m_playerInfo.creds;
	m_player.alignment = "Player";
	m_player.hpRegen = m_playerInfo.hpRegen;
	m_player.maxHealth = m_playerInfo.maxHealth;
	m_player.health = m_player.maxHealth;
	m_player.physicsInfo.maxVelocity = m_playerInfo.maxVelocity;
	m_player.physicsInfo.maxTurningSpeed = m_playerInfo.maxTurningSpeed;
	m_player.unitInfo.level = m_playerInfo.lvl;
	m_player.unitInfo.soundFile = m_playerInfo.soundFile;

	for(m_player.weaIter = m_playerInfo.weapons.begin(); m_player.weaIter != m_playerInfo.weapons.end(); m_player.weaIter++) {
		m_player.weapons.push_back(*m_player.weaIter);
	}

	if(!playerFound) {
		SHOWERROR("Player not Found!", __FILE__, __LINE__);
		system("PAUSE");
		exit(1);
	}
}

void GameApp::scaleDataToLevel(ITERATOR(WorldObject) iter) {
	if(iter->unitInfo.level == 0)
		iter->unitInfo.level = m_player.unitInfo.level;
	
	if(iter->value == 0)
		iter->value = iter->unitInfo.level;
	else
		iter->value += (int)ceil((double)((float)iter->unitInfo.level * g_ValueModifier));

	iter->maxHealth += (iter->maxHealth * g_MaxHpModifier) * iter->unitInfo.level;
	
	for(iter->weaIter = iter->weapons.begin(); iter->weaIter != iter->weapons.end(); iter->weaIter++)
		iter->weaIter->weaponDmg += (iter->weaIter->weaponDmg * g_WeaponDmgModifier) * iter->unitInfo.level;
	
	iter->physicsInfo.maxVelocity += (iter->physicsInfo.maxVelocity * g_MaxVelocityModifier) * iter->unitInfo.level;
	iter->physicsInfo.maxTurningSpeed += (iter->physicsInfo.maxTurningSpeed * g_MaxTurningSpeedModifier) * iter->unitInfo.level;
}

void GameApp::addRandomancyToData(ITERATOR(WorldObject) iter) {
	int randomNum = 0;
	float num = 0.0f;

	randomNum = rand() % g_MaxVelocityModifier2; // number from 0-g_MaxVelocityModifier2 (20) - 1
	num = (float)randomNum / 100.0f;
	num *= iter->physicsInfo.maxVelocity;

	randomNum = rand() % 2; // 0-1
	if(randomNum == 0)
		num = -num;

	iter->physicsInfo.maxVelocity += num;

	randomNum = rand() % g_MaxTurningSpeedModifier2; // number from 0-g_MaxVelocityModifier2 (20) - 1
	num = (float)randomNum / 100.0f;
	num *= iter->physicsInfo.maxTurningSpeed;

	randomNum = rand() % 2; // 0-1
	if(randomNum == 0)
		num = -num;

	iter->physicsInfo.maxTurningSpeed += num;
}


/*************************************************
			WINMAIN (Program Entrance)
*************************************************/

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
	// Creates a windows console, mainly for debugging purposes.
	// Use the PRINT(); function to output text. Refer to stdafx.h for the definition of PRINT();
	// Use NEXT_LINE to move the cursor to the next line.
	AllocConsole();
	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coord = {100,120};
	SetConsoleScreenBufferSize(console, coord);
	_cprintf("-- Debugger --\n\n");

	// Create the GameApp and Framework objects
	GameApp* pApplication = new GameApp();
	Framework* pFramework = new Framework((BaseApp*)pApplication);

	pApplication->SetFramework(pFramework);

	// Initialize any application resources
	if(!pApplication->Initialize()) {
		SHOWERROR("pApplication->Initialize() - Failed", __FILE__, __LINE__);
		return 0;
	}

	// Initialize the Framework
	if(!pFramework->Initialize("Terminal Velocity", hInstance, 1280, 720)) {
		SHOWERROR("pFramework->Initialize() - Failed", __FILE__, __LINE__);
		return 0;
	}

	// Rock and roll
	pFramework->Run();

	// Clean up resources
	SAFE_RELEASE(pApplication);

	return 0;
}